package vip.liux.front.infrastructure.utils;

import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class ListJoinKit {

    public <T> Long sum(List<T> list, Function<? super T, Long> mapper) {
        return list.stream().mapToLong(mapper::apply).reduce(0L, Long::sum);
    }

    public <T> Long sum(List<T> list, Function<? super T, Long> mapper, long defaultValue) {
        return list.stream().mapToLong(mapper::apply).reduce(defaultValue, Long::sum);
    }

    public <T> Long count(List<T> list, Predicate<? super T> predicate) {
        return list.stream().filter(predicate).count();
    }

    public <T> Map<?, T> toMap(List<T> list, Function<? super T, ?> keyMapper) {
        return list.stream().collect(Collectors.toMap(keyMapper, r -> r, (existing, replacement) -> existing));
    }

    public <T> Map<?, List<T>> groupBy(List<T> list, Function<? super T, ?> keyMapper) {
        return list.stream().collect(Collectors.groupingBy(keyMapper));
    }

    /**
     * 将右列表中的数据填充到左列表中
     *
     * @param leftList          左列表
     * @param rightList         右列表
     * @param rightKeyMapper    右列表的键映射函数
     * @param leftKeyMapper     左列表的键映射函数
     * @param leftValueConsumer 左列表的值消费函数
     * @param <L>               左列表元素类型
     * @param <R>               右列表元素类型
     */
    public <L, R> void backFill(
            List<L> leftList, List<R> rightList,
            Function<? super R, ?> rightKeyMapper,
            Function<L, ?> leftKeyMapper,
            BiConsumer<L, R> leftValueConsumer
    ) {
        backFill(leftList, rightList, rightKeyMapper, leftKeyMapper, leftValueConsumer, null);
    }

    /**
     * 将右列表中的数据填充到左列表中
     *
     * @param leftList           左列表
     * @param rightList          右列表
     * @param rightKeyMapper     右列表的键映射函数
     * @param leftKeyMapper      左列表的键映射函数
     * @param leftValueConsumer  左列表的值消费函数
     * @param rightValueConsumer 右列表的值消费函数
     * @param <L>                左列表元素类型
     * @param <R>                右列表元素类型
     */
    public <L, R> void backFill(
            List<L> leftList, List<R> rightList,
            Function<? super R, ?> rightKeyMapper,
            Function<L, ?> leftKeyMapper,
            BiConsumer<L, R> leftValueConsumer,
            Consumer<L> rightValueConsumer
    ) {

        // 将右列表转换为键值对映射
        Map<?, R> joinMap = toMap(rightList, rightKeyMapper);

        // 遍历左列表，根据键映射填充右列表的数据
        leftList.forEach(l -> {
            Object key = leftKeyMapper.apply(l);
            R r = joinMap.get(key);
            if (r != null) {
                if (leftValueConsumer != null) {
                    leftValueConsumer.accept(l, r);
                }
            } else {
                if (rightValueConsumer != null) {
                    rightValueConsumer.accept(l);
                }
            }
        });
    }

    /**
     * 将右列表中的数据填充到左列表中
     *
     * @param leftList          左列表
     * @param rightList         右列表
     * @param rightKeyMapper    右列表的键映射函数
     * @param leftKeyMapper     左列表的键映射函数
     * @param leftValueConsumer 左列表的值消费函数
     * @param <L>               左列表元素类型
     * @param <R>               右列表元素类型
     */
    public <L, R> void backFillToMany(
            List<L> leftList, List<R> rightList,
            Function<? super R, ?> rightKeyMapper,
            Function<L, ?> leftKeyMapper,
            BiConsumer<L, List<R>> leftValueConsumer
    ) {
        backFillToMany(leftList, rightList, rightKeyMapper, leftKeyMapper, leftValueConsumer, null);
    }

    /**
     * 将右列表中的数据填充到左列表中
     *
     * @param leftList           左列表
     * @param rightList          右列表
     * @param rightKeyMapper     右列表的键映射函数
     * @param leftKeyMapper      左列表的键映射函数
     * @param leftValueConsumer  左列表的值消费函数
     * @param rightValueConsumer 右列表的值消费函数
     * @param <L>                左列表元素类型
     * @param <R>                右列表元素类型
     */
    public <L, R> void backFillToMany(
            List<L> leftList, List<R> rightList,
            Function<? super R, ?> rightKeyMapper,
            Function<L, ?> leftKeyMapper,
            BiConsumer<L, List<R>> leftValueConsumer,
            Consumer<L> rightValueConsumer
    ) {

        // 将右列表转换为键值对映射
        Map<?, List<R>> joinMap = groupBy(rightList, rightKeyMapper);

        // 遍历左列表，根据键映射填充右列表的数据
        leftList.forEach(l -> {
            Object key = leftKeyMapper.apply(l);
            List<R> rs = joinMap.getOrDefault(key, List.of());
            if (rs.isEmpty()) {
                if (leftValueConsumer != null) {
                    leftValueConsumer.accept(l, rs);
                }
            } else {
                if (rightValueConsumer != null) {
                    rightValueConsumer.accept(l);
                }
            }
        });
    }

    public <L, R1, R2> void backFill(
            List<L> leftList, List<R1> rightList1, List<R2> rightList2,
            Function<? super R1, ?> right1KeyMapper,
            Function<? super R2, ?> right2KeyMapper,
            Function<L, ?> leftKeyMapper,
            BiConsumer<L, R1> leftValueConsumer1,
            BiConsumer<L, R2> leftValueConsumer2,
            Consumer<L> rightValueConsumer
    ) {
        // 将右列表转换为键值对映射
        Map<?, R1> joinMap1 = toMap(rightList1, right1KeyMapper);
        Map<?, R2> joinMap2 = toMap(rightList2, right2KeyMapper);

        // 遍历左列表，根据键映射填充右列表的数据
        leftList.forEach(l -> {
            Object key = leftKeyMapper.apply(l);
            R1 r1 = joinMap1.get(key);
            if (r1 != null) {
                if (leftValueConsumer1 != null) {
                    leftValueConsumer1.accept(l, r1);
                }
            } else {
                if (rightValueConsumer != null) {
                    rightValueConsumer.accept(l);
                }
            }

            R2 r2 = joinMap2.get(key);
            if (r2 != null) {
                if (leftValueConsumer2 != null) {
                    leftValueConsumer2.accept(l, r2);
                }
            } else {
                if (rightValueConsumer != null) {
                    rightValueConsumer.accept(l);
                }
            }
        });
    }
}